#include <stdio.h>
#include "ListaAresta.h"
#include "SolucaoGRASPSTS.h"
#include "Kruskal.h"

#define MAX_CUSTO 10000

SolucaoGRASPSTS::SolucaoGRASPSTS(int tam){
	 tamanho = tam;
	 cliAlocado = 0;
	 this->saida  = new char[tamanho+1];
         this->solucao = new bool[tamanho];
}

SolucaoGRASPSTS::SolucaoGRASPSTS(SolucaoGRASPSTS *sol){
	cliAlocado = 0;
	this->saida  = new char[sol->tamanho+1];
	this->solucao = new bool[sol->tamanho];
	this->avaliacao = sol->avaliacao;
	//for(int i=0; i<tamanho; i++)
	//	this->solucao[i] = sol->solucao[i];
	memcpy(this->solucao, sol->solucao, sol->tamanho * sizeof(char));
}
SolucaoGRASPSTS::SolucaoGRASPSTS(char *s){
	cliAlocado = 0;
	this->saida  = new char[tamanho+1];
	memcpy(this->saida, s, strlen(s) * sizeof(char));
	this->solucao = new bool[tamanho];
	int count = 0;
	while(s[count] != '\0'){
		if(s[count] == '0')
			solucao[count] = false;
		else
			solucao[count] = true;
		++count;
	}
}

void SolucaoGRASPSTS::init(){
	for(int i = 0; i < tamanho; i++)
		this->solucao[i] = false;
		/*this->solucao[2] = true;
		this->solucao[3] = true;
		this->solucao[5] = true;
		this->solucao[6] = true;*/
}

bool SolucaoGRASPSTS::todosClientesAlocados(){
	//printf("NALOC: %d\n", cliAlocado);
	//double d = (double)numClient + var*(double)capacidadeSuperior;
	//printf("d: %f\n", d);
	return (cliAlocado >= numClient + capacidadeSuperior);
}

double SolucaoGRASPSTS::fc(){
	int tamLigacao = tamanho * numClient;
        double soma = 0;
        int auxCapacidade[tamanho];
	int ativos[tamanho];
        int nAtivos = 0;
	for(int i=0; i < tamanho; i++){
                auxCapacidade[i] = capacidadeSteiner[i];
		if(solucao[i] == true){
			ativos[nAtivos]=i; 
			nAtivos++;
		}
			
	}

        for(register int i=0; i<numClient; i++){
                double c = MAX_CUSTO;
                int pos = 0;
		int k;
                for(int j = 0; j < nAtivos; j++){
			if(auxCapacidade[ativos[j]]!=0){
				k = ativos[j]*numClient;
                                if(c > linkClient[k + i]){
                                        c  = linkClient[k + i];
                                        pos = ativos[j];
                                }
                        }
                }
                //printf("CLI: %d, STE: %d\n", i, pos);
                soma += c;
                auxCapacidade[pos]--;//printf("P: %d\n", pos);
        }
        //printf("FC: %f\n", soma);
        return soma;
}

/*double SolucaoGRASPSTS::fc(){
	int tamLigacao = tamanho * numClient;
	double soma = 0;
	int auxCapacidade[tamanho];
	int atribuicao[numClient];
	int select = numClient + 1;
	bool solServer[tamanho];
	//double custo[tamLigacao];

	for(int i=0; i < tamanho; i++){
		auxCapacidade[i] = capacidadeSteiner[i];
		solServer[i] = this->solucao[i];
	}
	
	for(int j = 0; j < numClient; j++)
		atribuicao[j] = j;

	//Coloca o apontador do menor custo para o proximo
	//custoClientSteiner->resetNext();
	int nAlocadoCli = 0;
	for(register int i=0; nAlocadoCli<numClient; i++){
		if((atribuicao[indClient[i]] != select)&&(solServer[indServidor[i]] == true)){
			if(auxCapacidade[indServidor[i]]!=0){
				atribuicao[indClient[i]] = select;
				soma  += indCusto[i];
				++nAlocadoCli;
				auxCapacidade[indServidor[i]]--;
			}
		}
		//delete aux;
			
	}
	//printf("FC: %f\n", soma);
	return soma;
}
*/
double SolucaoGRASPSTS::fl(){
	Kruskal k(this);
	double d =  k.getSomaArestas();
	//printf("FL: %f\n", d);
	return d;
}

double SolucaoGRASPSTS::fs(){
	double soma = 0;
	for(int i=0; i<tamanho; i++){
		if(this->solucao[i]){
			soma += custoSteiner[i];
			//printf("C: %d S: %f\n", custoSteiner[i], soma);
		}
	}
	//printf("FS: %f\n", soma);
	return soma;
}

double SolucaoGRASPSTS::validate(){
	int soma = 0;
	for(int i=0; i<tamanho; i++){
		if(this->solucao[i])
			soma += capacidadeSteiner[i];
	}
	if(soma >= numClient)
		return 0;
	else
		return MAX_CUSTO;
}

double SolucaoGRASPSTS::f(){
	this->avaliacao = fc() + fl() + fs() + validate();
	return this->avaliacao;
}

double SolucaoGRASPSTS::gc(int pos){
	double media = 0;
	int offset = numClient * pos;
	if(isInitGulosa){
		for(int i=0; i<numClient; i++){
			media += linkClient[offset + i];
		}
		media /= numClient;
	}else{
		int cli = 0;
		for(int i=0; i<numClient; i++){
			if(auxLinkClient[i] > linkClient[offset + i]){
				media += linkClient[offset + i];
				cli++;
			}
		}
		if(media != 0)
			media /= cli;
		else
			return MAX_CUSTO;
	}
	return media;
}

double SolucaoGRASPSTS::gl(int pos){
	double menor = MAX_CUSTO;
	for(int i=0, k=0; i < tamanho; i++){
		if(this->solucao[i] == true){	
			int ind = pos - (i + 1);	
			if(menor > linkSteiner[k + ind])
				menor = linkSteiner[k + ind];
		}
		if(i == pos){
			for(int j=i+1; j < tamanho; j++){
				if(this->solucao[j] == true){	
					if(menor > linkSteiner[k])
						menor = linkSteiner[k];
					k++;
				}else
					k++;
				
			}
			return menor;
		}else{
			k += (tamanho - i - 1);
		}
	}
	return menor;
}

double SolucaoGRASPSTS::gs(int pos){
	return custoSteiner[pos];
}

double SolucaoGRASPSTS::g(int pos){
	return this->gc(pos) + this->gl(pos) + this->custoSteiner[pos];
}

#include "Lista.h"

void SolucaoGRASPSTS::setElemento(int pos){
	int offset = numClient * pos;
	//Armazenando o vetor dos links dos clientes com o Steiner escolhido
	if(isInitGulosa){
		for(int i=0; i<numClient; i++)
			auxLinkClient[i] = linkClient[offset + i];
	}else{
		for(int i=0; i<numClient; i++){
			if(auxLinkClient[i] > linkClient[offset + i])
				auxLinkClient[i] = linkClient[offset + i];
			
		}
	}
	isInitGulosa = false;
	cliAlocado += capacidadeSteiner[pos];
	this->solucao[pos] = true;
}

SolucaoGRASPSTS *SolucaoGRASPSTS::getVizinho(int mov){
	SolucaoGRASPSTS *s = new SolucaoGRASPSTS(this); 
	s->mov = mov;
	if(s->solucao[mov] == true)
		s->solucao[mov] = false;
	else
		s->solucao[mov] = true;
	s->f();
	return s;
}


SolucaoGRASPSTS *SolucaoGRASPSTS::getSWAP(int i, int j){
	SolucaoGRASPSTS *s = new SolucaoGRASPSTS(this); 
	s->mov = i;
	bool b = s->solucao[i];
	s->solucao[i] = s->solucao[j];
	s->solucao[j] = b;	
	s->f();
	return s;
}

SolucaoGRASPSTS *SolucaoGRASPSTS::getVizinhosADD(){
        SolucaoGRASPSTS *solAdd = new SolucaoGRASPSTS(this);
        for(int i=0; i < this->tamanho; i++){
                if(this->solucao[i] == false){
			//if( (rand()%100) >= 50){
				SolucaoGRASPSTS *sol = this->getVizinho(i);
				if(sol->avaliacao < solAdd->avaliacao){
					delete solAdd;
					solAdd = sol;
				}else
					delete sol;
	                        //printf("Viz: %s \n", sol->print());
        	                //printf("Viz: %s \n", sol->print());
                	        //printf("f: %f \n",sol->avaliacao);
        		//}
 	       }
        }
        return solAdd;
}

SolucaoGRASPSTS *SolucaoGRASPSTS::getVizinhosDROP(){
        SolucaoGRASPSTS *solDrop = new SolucaoGRASPSTS(this);
        for(int i=0; i < this->tamanho; i++){
                if(this->solucao[i] == true){
			//if( (rand()%100) >= 50){
                        	SolucaoGRASPSTS *sol = this->getVizinho(i);
				if(sol->avaliacao < solDrop->avaliacao){
					delete solDrop;
					solDrop = sol;
				}else
					delete sol;
	                        //printf("Viz: %s \n", sol->print());
        	                //printf("Viz: %s \n", sol->print());
                	        //printf("f: %f \n",sol->avaliacao);
			//}
                }
        }
        return solDrop;
}

SolucaoGRASPSTS *SolucaoGRASPSTS::getVizinhosSWAP(){
        SolucaoGRASPSTS *solSwap = new SolucaoGRASPSTS(this);
	for(int i=0; i < this->tamanho; i++){
                for(int j = i+1; j < this->tamanho; j++){
			if(solucao[i] != solucao[j]){
				//if( (rand()%100) >= 50){
					SolucaoGRASPSTS *sol = this->getSWAP(i, j);
					if(sol->avaliacao < solSwap->avaliacao){
						delete solSwap;
						solSwap = sol;
					}else
						delete sol;
                			//printf("Viz: %s \n", sol->print());
                			//printf("f: %f \n",sol->avaliacao);
				//}
			}
		}
        }
        return solSwap;
}

